﻿//--------------------------------------------------------------------------------------------------------------------------------------------------------
// <copyright file="RegisteringAUser.cs">
//     Copyright © 2010 Oli Francis
//     This source code is subject to the terms and conditions of the MIT license. A copy of the license can be found in the license.txt 
//     file at the root of this distribution. By using this source code in any fashion, you are agreeing to be bound by the terms of the MIT License. 
//     You must not remove this notice from the software.
// </copyright>
// <author>Oli</author>
//-------------------------------------------------------------------------------------------------------------------------------------------------------

namespace TeamBrain.Tests.Units.Registration
{
    using System;
    using Moq;
    using NUnit.Framework;

    using TeamBrain.Domain.Core;
    using TeamBrain.Domain.Core.Repositories;
    using TeamBrain.Domain.Model;
    using TeamBrain.Domain.Services;
    using TeamBrain.Domain.Services.Email;
    using TeamBrain.Domain.Services.Exceptions;
    using TeamBrain.Domain.Services.Registration;
    using TeamBrain.Domain.Services.Security;

    [TestFixture]
    [Category("Units")]
    [Category("Registration")]
    public class RegisteringAUser : RegistrationAction
    {
        [Test]
        [ExpectedException(typeof(EmailAlreadyRegisteredException))]
        public void ShouldThrowExceptionIfEmailAddressIsAlreadyRegistered()
        {
            // arrange
            this.UserRepository.Setup(r => r.GetByEmailAddress(It.IsAny<string>())).Returns(new User());

            // act
            this.RegistrationService.RegisterNewUser(new User());
        }

        [Test]
        public void ShouldSendAnEmailToVerifyTheirEmailAddress()
        {
            // act
            this.RegistrationService.RegisterNewUser(new User());

            // assert
            this.EmailService.Verify(e => e.SendUserActivationEmail(It.IsAny<User>()));
        }

        [Test]
        public void ShouldCreateANewUserRecord()
        {
            // act
            this.RegistrationService.RegisterNewUser(new User());

            // assert
            this.UserRepository.Verify(r => r.Add(It.IsAny<User>()));
            this.UnitOfWork.Verify(u => u.Flush());
        }

        [Test]
        public void ShouldMarkTheNewUserAsNotYetActive()
        {
            // arrange
            var user = new User();

            // act
            this.RegistrationService.RegisterNewUser(user);

            // assert
            Assert.IsFalse(user.IsActive);
        }

        [Test]
        public void ShouldGenerateAUniqueActivationToken()
        {
            // arrange
            var user1 = new User();
            var user2 = new User();

            // act
            this.RegistrationService.RegisterNewUser(user1);
            this.RegistrationService.RegisterNewUser(user2);

            // assert
            Assert.IsNotNullOrEmpty(user1.ActivationToken);
            Assert.IsNotNullOrEmpty(user2.ActivationToken);
            Assert.AreNotEqual(user1.ActivationToken, user2.ActivationToken);
            Assert.Greater(user1.ActivationToken.Length, 5);
            Assert.Less(user1.ActivationToken.Length, 40);
        }

        [Test]
        public void ShouldStoreHashedPassword()
        {
            // arrange
            var user = new User { Password = "Bor1s" };
            this.PasswordHasher.Setup(h => h.GetNewSalt()).Returns("Salty").Verifiable();
            this.PasswordHasher.Setup(h => h.GetPasswordHash("Salty", "Bor1s")).Returns("HASHVALUE").Verifiable();

            // act
            this.RegistrationService.RegisterNewUser(user);

            // assert
            this.PasswordHasher.VerifyAll();
            Assert.AreEqual(user.Salt, "Salty");
            Assert.AreEqual(user.PasswordHash, "HASHVALUE");
            Assert.IsNullOrEmpty(user.Password);
        }
    }
}
